package cn.android666.getip

import android.Manifest
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.annotation.RequiresPermission
import timber.log.Timber
import java.net.Inet4Address
import java.net.Inet6Address
import java.net.InetAddress
import java.net.NetworkInterface

object NetUtil {

    data class NetInterface(val name: String?, val ipv4: String?, val ipv6: String?)

    fun getNetInterface(): NetInterface? {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            getActiveNetInterface()
        } else {
            val netInterfaceList = getNetInterfaceList()
            val vpn = netInterfaceList.firstOrNull { it.name == "tun0" }
            val wifi = netInterfaceList.firstOrNull { it.name == "wlan0" }
            // rmnet0, rmnet1, … Qualcomm 手机常见移动数据接口
            // ccmni0, ccmni1, … MediaTek 手机常见移动数据接口
            // rmnet_data0 部分新版本 Qualcomm/Android 设备使用
            val mobile = netInterfaceList.firstOrNull { it.name == "rmnet0" || it.name == "ccmni0" || it.name == "rmnet_data0" }
            val first = netInterfaceList.firstOrNull()
            vpn ?: wifi ?: mobile ?: first
        }
    }

    /** 获取当前正在使用的网络接口 */
    @RequiresApi(Build.VERSION_CODES.M)
    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
    fun getActiveNetInterface(): NetInterface? {
        val cm = App.app.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        
        // Android 6.0开始才有activeNetwork方法，此方法需要ACCESS_NETWORK_STATE权限
        val activeNetwork =  cm.activeNetwork ?: return null
        
        val linkProperties = cm.getLinkProperties(activeNetwork) ?: return null
        val interfaceName = linkProperties.interfaceName
        val linkAddresses = linkProperties.linkAddresses
        val predicate = { ip: InetAddress -> ip.isLinkLocalAddress.not() } // 不能是链接本地地址的IP
        val ipv4 = linkAddresses.firstOrNull { it.address is Inet4Address && predicate(it.address) }?.address?.hostAddress
        val ipv6 = linkAddresses.firstOrNull { it.address is Inet6Address && predicate(it.address) }?.address?.hostAddress
        return NetInterface(interfaceName, ipv4, ipv6)
    }

    /** 获取所有有效的网络接口 */
    @RequiresPermission(allOf = [Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.INTERNET])
    fun getNetInterfaceList(): List<NetInterface> {
        val predicate = { ip: InetAddress -> ip.isLinkLocalAddress.not() } // 不能是链接本地地址的IP
        val ipv4Predicate = { ip: InetAddress -> ip is Inet4Address && predicate(ip) } // 只要IPv4的IP，且不能是链接本地地址的IP
        val ipv6Predicate = { ip: InetAddress -> ip is Inet6Address && predicate(ip) } // 只要IPv6的IP，且不能是链接本地地址的IP

        // 过滤出是up的，且不是回环的，且有有效ip的网络接口
        return NetworkInterface.getNetworkInterfaces().asSequence()
            .filter { it.isUp }
            .filter { it.isLoopback.not() }
            .filter { it.inetAddresses.asSequence().filter(predicate).any() }
            .map {
                val name = it.name
                val ipv4 = it.inetAddresses.asSequence().filter(ipv4Predicate).firstOrNull()?.hostAddress
                val ipv6 = it.inetAddresses.asSequence().filter(ipv6Predicate).firstOrNull()?.hostAddress
                NetInterface(name, ipv4, ipv6)
            }
            .toList()
    }

    @RequiresPermission(allOf = [Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.INTERNET])
    fun printAllInterfaces() {
        val start = System.currentTimeMillis()

        // 声明一个过滤有效ip的条件：且不能是链接本地地址的IP
        val predicate = { ip: InetAddress -> ip.isLinkLocalAddress.not() }

        // 过滤出是up的，且不是回环的，且有有效ip的网络接口
        NetworkInterface.getNetworkInterfaces().asSequence()
            .filter { it.isUp }
            .filter { it.isLoopback.not() }
            .filter { it.inetAddresses.asSequence().filter(predicate).any() }
            .forEach { ni: NetworkInterface ->
                Timber.i("interfaceName=${ni.name}, displayName=${ni.displayName}, isVirtual()=${ni.isVirtual}, isUp()=${ni.isUp}, isLoopback()=${ni.isLoopback}, supportsMulticast()=${ni.supportsMulticast()}, isPointToPoint()=${ni.isPointToPoint}")
                for (ia in ni.inetAddresses.asSequence().filter(predicate)) {
                    Timber.i("Address=${ia.hostAddress}, isLoopbackAddress=${ia.isLoopbackAddress}, isLinkLocalAddress=${ia.isLinkLocalAddress}, class=${ia.javaClass.name}")
                }
                Timber.i("------------------------------------------------------------------------")
            }

        Timber.i("结束，用时：${System.currentTimeMillis() - start}")
    }

    /** 获取wifi的路由ip地址（也就是网关，能过该网关ip就可以访问到球机） */
    fun getWifiRouteIpAddress(): String? {
        val cm = App.app.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val activeNetwork = cm.activeNetwork ?: return null
            val activeNetworkCapabilities = cm.getNetworkCapabilities(activeNetwork) ?: return null
            if (activeNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI).not()) {
                // 如果当前的活动网络并不是Wi-Fi网络
                Timber.i("当前活动网络不是Wi-Fi网络")
                return null
            }
            val linkProperties = cm.getLinkProperties(activeNetwork) ?: return null
            val defaultRouteInfo = linkProperties.routes.firstOrNull { it.isDefaultRoute && it.gateway is Inet4Address }
            return defaultRouteInfo?.gateway?.hostAddress
        } else {
            return null
        }
    }

}
